<?php

namespace App\Trip\Orders\BookOrders\Train\PriceDetails;

use App\Models\Setting\Setting;
use App\Models\Train\TrainOrderPassengers\TrainOrderPassenger;
use App\Models\Train\TrainOrders\TrainOrder;
use App\Models\Trip\TripOrderCosts\TripOrderCost;
use App\Trip\Orders\BookOrders\Train\PriceDetails\AbstractPriceDetails\AbstractPriceDetails;
use App\Trip\Orders\TripNo;
use App\Trip\Passengers\Passengers;
use App\Trip\Train\Order\Impl\PiaoChiOrderPassengerRefundImpl;
use Exception;

class ChangePriceDetails extends AbstractPriceDetails
{
    private array      $passengers;
    private TrainOrder $origin_order_info;
    private float      $service_fee;
    private array      $price_details;
    /**
     * @var float
     */
    private float $order_amount;
    private float $origin_order_need_refund_amount = 0;

    /**
     * @throws Exception
     */
    public function __construct(TrainOrder $origin_order_info, array $passengers)
    {
        $this->passengers        = $passengers;
        $this->origin_order_info = $origin_order_info;
        $this->service_fee       = $this->getServiceFee();
        $this->buildPriceDetails();
    }

    public function getServiceFee(): float
    {
        $setting = new Setting();
        return $setting->TrainOfflineChangeServiceFee();
    }

    /**
     * @inheritDoc
     * @throws Exception
     */
    private function buildPriceDetails()
    {
        /**
         * 是否有票价差
         */
        $isTicketPriceDiff = false;
        $passengers        = $this->passengers;
        $origin_passengers = $this->origin_order_info->getPassengers();
        $name              = TripNo::TRIP_NO_DESC[$this->origin_order_info->getTripNo()];
        $details           = [];
        $total_price       = 0;
        /**
         * @var TrainOrderPassenger $origin_order_passenger
         */
        foreach ($passengers as $key => $passenger) {
            $passenger_type = $passenger['passenger_type'];
            if (!isset($passenger['origin_passenger'])) {
                $origin_passenger                     = $origin_passengers
                    ->where('passenger_id', $passenger['passenger_id'])
                    ->where('sequence', $passenger['sequence'])
                    ->firstWhere('passenger_type', $passenger_type);
                $passengers[$key]['origin_passenger'] = $passenger['origin_passenger'] = $origin_passenger;
            }

            $origin_order_passenger = $passenger['origin_passenger'];
            $passenger_type_name    = Passengers::PASSENGER_TYPE_DESC[$passenger_type];

            /**
             * 票价 如果老价格和新价格一致 则无票价
             */
            $ticket_price_key                             = "ticket_price:".$passenger_type_name;
            $passengers[$key]['origin_order_need_refund'] = 0;
            $passengers[$key]['service_fee']              = $this->getServiceFee();
            if (!$this->equalPriceOrIsChild($origin_order_passenger, $passenger)) {
                $isTicketPriceDiff = true;
                if (!isset($details[$ticket_price_key])) {
                    $details[$ticket_price_key] = [
                        "type"        => TripOrderCost::COST_TYPE_TICKET,
                        "parent_type" => TripOrderCost::COST_TYPE_TICKET,
                        "name"        => $passenger_type_name,
                        "name_uy"     => trans2uy($passenger_type_name),
                        "price"       => $passenger['seat_price'],
                        "count"       => 1,
                    ];
                } else {
                    $details[$ticket_price_key]["count"]++;
                }
                $total_price                                  += $passenger['seat_price'];
                $order_passenger_refund                       = new PiaoChiOrderPassengerRefundImpl($this->origin_order_info, $passenger['origin_passenger']);
                $passengers[$key]['origin_order_need_refund'] = $order_passenger_refund->ticketRefundAmount();
                $passengers[$key]['change_ticket_loss']       = $order_passenger_refund->ticketLossAmount();
                $this->origin_order_need_refund_amount        += $passengers[$key]['origin_order_need_refund'];
                $passengers[$key]['price_details'][]          = [
                    "type"        => TripOrderCost::COST_TYPE_TICKET,
                    "parent_type" => TripOrderCost::COST_TYPE_TICKET,
                    "name"        => Passengers::PASSENGER_TYPE_DESC[$passenger_type],
                    "price"       => $passengers[$key]['seat_price'],
                ];
            }
            // 保存原票票价
            $passengers[$key]['origin_ticket_price'] = $origin_order_passenger->getTicketPrice();
            $ticket_service_key                      = "change_service_fee";
            $ticket_service_type                     = TripOrderCost::COST_TYPE_CHANGE_SERVICE_FEE;
            /**
             * 改签手续费 必收
             */
            $passengers[$key]['price_details'][] = [
                "type"        => TripOrderCost::COST_TYPE_CHANGE_SERVICE_FEE,
                "parent_type" => TripOrderCost::COST_TYPE_CHANGE_SERVICE_FEE,
                "name"        => "改签手续费",
                "price"       => $passengers[$key]['service_fee'],
            ];
            $ticket_service_name                 = "改签手续费";
            if (!isset($details[$ticket_service_key])) {
                $details[$ticket_service_key] = [
                    "type"        => $ticket_service_type,
                    "parent_type" => $ticket_service_type,
                    "name"        => $ticket_service_name,
                    "name_uy"     => trans2uy($ticket_service_name),
                    "price"       => $this->getServiceFee(),
                    "count"       => 1,
                ];
            } else {
                $details[$ticket_service_key]["count"]++;
            }
            $total_price += $this->getServiceFee();
        }
        if (empty($passengers)) {
            throw new Exception('暂无可改签的乘客');
        }
        $this->passengers    = $passengers;
        $this->order_amount  = $total_price;
        $tip                 = $isTicketPriceDiff ? "改签车次与原车次存在差价，我们将先收取改签车次票价，改签成功后退还差价" : "注意：改签需要去火车站进行改签，所以我们改签过程会收服务费";
        $this->price_details = [
            'name'        => $name,
            'name_uy'     => trans2uy($name),
            "total_price" => $total_price,
            "tip"         => __($tip),
            'details'     => collect($details)->sortBy('type')->values()->toArray(),
        ];
    }

    public function getPassengers(): array
    {
        return $this->passengers;
    }

    private function equalPriceOrIsChild(TrainOrderPassenger $origin_order_passenger, $passenger): bool
    {
        if ($origin_order_passenger->getTicketPrice() != $passenger['seat_price']) {
            if ($origin_order_passenger->isChild()) {
                if ($origin_order_passenger->getSeatPrice() != $passenger['seat_price']) {
                    return false;
                }
            } else {
                return false;
            }
        }
        return true;
    }

    public function getPriceDetails(): array
    {
        return $this->price_details;
    }

    /**
     * @inheritDoc
     * @throws Exception
     */
    public function calcReceivable(): float
    {
        return $this->getOrderAmount();
    }

    /**
     * 如果票价 一致不收取票价
     * 如果票价不一致  原票退款 ,新票收费
     * 当前策略 如果是儿童票 如果 票价和源座位价格一样 不收取  改签成功 不退原票
     *
     * @inheritDoc
     */
    public function getOrderAmount(): float
    {
        return $this->order_amount;
    }

    /**
     * 原订单需退款金额
     *
     * @throws Exception
     */
    public function calcOriginNeedRefundAmount(): float
    {
        return $this->origin_order_need_refund_amount;

    }
}